home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Tools 4
/
Amiga Tools 4.iso
/
tools
/
netzwerk
/
tcp-ip
/
ipdial_v1.9
/
serial.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-02-26
|
17KB
|
749 lines
/**
*** IPDial Script program for initializing a SLIP connection
*** Copyright (C) 1994 Jochen Wiedmann
***
*** This program is free software; you can redistribute it and/or modify
*** it under the terms of the GNU General Public License as published by
*** the Free Software Foundation; either version 2 of the License, or
*** (at your option) any later version.
***
*** This program is distributed in the hope that it will be useful,
*** but WITHOUT ANY WARRANTY; without even the implied warranty of
*** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*** GNU General Public License for more details.
***
*** You should have received a copy of the GNU General Public License
*** along with this program; if not, write to the Free Software
*** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
***
***
***
*** This file implements the communication with the serial.device.
***
***
*** Computer: Amiga 1200 Compiler: Dice 3.01
***
*** Author: Jochen Wiedmann
*** Am Eisteich 9
*** 72555 Metzingen
*** Germany
***
*** Phone: (+0049) 7123 / 14881
*** Internet: wiedmann@neckar-alb.de
**/
/**
*** Include files
**/
#ifndef IPDIAL_H
#include "IPDial.h"
#endif
#include <ctype.h>
#include <devices/serial.h>
#include <devices/timer.h>
#ifndef MIN
#define MIN(a,b) (((a)>(b))?(b):(a))
#endif
/**
*** Local variables.
**/
STATIC APTR MySerReq = NULL;
STATIC APTR MyTimeReq = NULL;
STATIC UBYTE SerBuffer[4096];
/**
*** Cleanup function.
**/
VOID SerialCleanup(VOID)
{
DeviceIODelete(MySerReq);
DeviceIODelete(MyTimeReq);
}
/**
*** Table of error messages created by the serial.device.
**/
STATIC VOID SerialShowError(ULONG Error)
{
STRPTR ptr;
switch(Error)
{ case 1:
ptr = (STRPTR) "Serial device busy";
break;
case 2:
ptr = (STRPTR) "Baud rate not supported";
break;
case 4:
ptr = (STRPTR) "Memory error";
break;
case 5:
ptr = (STRPTR) "Invalid parameters";
break;
case 6:
ptr = (STRPTR) "Line error";
break;
case 9:
ptr = (STRPTR) "Parity error";
break;
case 11:
ptr = (STRPTR) "Timer error";
break;
case 12:
ptr = (STRPTR) "Buffer overflow";
break;
case 13:
ptr = (STRPTR) "No DSR";
break;
case 15:
ptr = (STRPTR) "Break detected";
break;
default:
ptr = (STRPTR) "Unknown error";
break;
}
fprintf(stderr, "Serial device: %s.\n", ptr);
}
/**
*** This function opens the serial device. It can be closed
*** using DeviceIODelete().
**/
STATIC ULONG SerialDecodeProtocol(struct IOExtSer *SerReq, STRPTR Protocol)
{
if (VerboseMode)
printf("\nSerialDecodeProtocol: Protocol %s\n", Protocol);
if (stricmp((char *) Protocol, "XONXOFF") == 0)
{
if (VerboseMode)
printf("SerialDecodeProtocol: Setting XON/XOFF\n");
SerReq->io_SerFlags &= ~(SERF_XDISABLED|SERF_7WIRE);
}
else if (stricmp((char *) Protocol, "NONE") == 0)
{
if (VerboseMode)
printf("SerialDecodeProtocol: Setting NONE\n");
SerReq->io_SerFlags |= SERF_XDISABLED;
SerReq->io_SerFlags &= ~SERF_7WIRE;
}
else if (stricmp((char *) Protocol, "RTSCTS") == 0 ||
stricmp((char *) Protocol, "7WIRE") == 0)
{
if (VerboseMode)
printf("SerialDecodeProtocol: Setting RTS/CTS and 7WIRE\n");
SerReq->io_SerFlags |= (SERF_XDISABLED|SERF_7WIRE);
}
else
{
if (VerboseMode)
printf("SerialDecodeProtocol: Unknown Protocol: %s\n", Protocol);
return(FALSE);
}
return(TRUE);
}
ULONG SerialOpen(STRPTR DeviceName, STRPTR Protocol, ULONG Unit)
{
ULONG error;
struct IOExtSer *RealSerReq;
if (VerboseMode)
printf("\nSerialOpen: Device Name %s Protocol %s\n", DeviceName, Protocol);
if (!(MySerReq = DeviceIOCreate(sizeof(struct IOExtSer))))
{
fprintf(stderr, "Failed to open %s: Memory error.\n",
DeviceName);
exit(10);
}
RealSerReq = (struct IOExtSer *) DeviceIOReq(MySerReq);
RealSerReq->io_SerFlags = 0;
if (Protocol)
{
if (!SerialDecodeProtocol(RealSerReq, Protocol))
{
return(FALSE);
}
}
if ((error = DeviceIOOpen(DeviceName, Unit, MySerReq, 0)))
{
SerialShowError(error);
exit(10);
}
if (Protocol)
{
SerialSetProtocol(Protocol);
}
if (!(MyTimeReq = DeviceIOCreate(sizeof(struct timerequest))))
{
fprintf(stderr, "Failed to open timer.device: Memory error.\n");
exit(10);
}
if ((error = DeviceIOOpen((STRPTR) "timer.device", UNIT_VBLANK,
MyTimeReq, 0)))
{
fprintf(stderr, "Failed to open timer.device: Error %ld\n", error);
exit(10);
}
return(TRUE);
}
/**
*** This function sends a string to the serial device.
**/
VOID SerialSend(STRPTR str, ULONG len)
{
struct IOExtSer *req;
if (VerboseMode)
printf("\nSerialSend: %s\n", str);
req = (struct IOExtSer *) DeviceIOReq(MySerReq);
req->IOSer.io_Length = strlen((char*) str);
req->IOSer.io_Data = str;
DeviceIODo(MySerReq, CMD_WRITE);
}
/**
*** This function is used to wait for a certain string.
***
*** The function will return if either a timeout occurs
*** (never happens, if timeout == -1) or if one of the
*** strings in the args array is read from the serial.device.
***
*** Result is the number of the string or -1.
**/
STATIC APTR waitBuffer = NULL;
LONG SerialWait(STRPTR *args, LONG timeout)
{
ULONG sigs;
ULONG rsigs;
BYTE error;
struct IOExtSer *SerReq;
if(VerboseMode)
{
int i=0;
printf("SerialWait: timeout = %d\n",timeout);
while(args[i])
{
printf("SerialWait: args[%d] %s \n",i,args[i]);
i++;
}
}
SerReq = (struct IOExtSer *) DeviceIOReq(MySerReq);
/**
*** Be sure, that the buffer is valid.
**/
if (!waitBuffer && !(waitBuffer = BufferCreate()))
{
perror("malloc");
exit(10);
}
/**
*** Clear the buffer.
**/
BufferClear(waitBuffer);
sigs = SIGBREAKF_CTRL_C | DeviceIOSignal(MySerReq);
if (timeout != -1)
{
struct timerequest *tr = (struct timerequest *) DeviceIOReq(MyTimeReq);
tr->tr_time.tv_secs = timeout;
tr->tr_time.tv_micro = 0;
DeviceIOSend(MyTimeReq, TR_ADDREQUEST);
sigs |= DeviceIOSignal(MyTimeReq);
}
for(;;)
{
LONG result;
/**
*** First ask, if any data is present on the serial line.
*** May be, the string we are waiting for is already present?
**/
do
{
DeviceIODo(MySerReq, SDCMD_QUERY);
if ((result = SerReq->IOSer.io_Actual))
{
SerReq->IOSer.io_Data = SerBuffer;
SerReq->IOSer.io_Length = MIN(sizeof(SerBuffer)-1,
SerReq->IOSer.io_Actual);
if ((error = DeviceIODo(MySerReq, CMD_READ)))
{
SerialShowError(error);
exit(10);
}
if (EchoMode)
{
int i;
for (i = 0; i < SerReq->IOSer.io_Actual; i++)
{
putchar(SerBuffer[i]);
}
fflush(stdout);
}
BufferExtend(waitBuffer, SerBuffer, SerReq->IOSer.io_Actual);
}
}
while (result);
if ((result = BufferCheck(waitBuffer, args)) >= 0)
{
DeviceIOAbort(MyTimeReq);
if(VerboseMode)
printf("SerialWait: Exit line %d result = %d\n",__LINE__,result);
return(result);
}
/**
*** It isn't, send a request for one byte.
**/
SerReq->IOSer.io_Length = 1;
SerReq->IOSer.io_Data = SerBuffer;
DeviceIOSend(MySerReq, CMD_READ);
rsigs = Wait(sigs);
if (rsigs & SIGBREAKF_CTRL_C)
{
printf("Ctrl-C\n");
exit(10);
}
else if (rsigs & DeviceIOSignal(MySerReq))
{
BYTE error;
/**
*** Data received, add it to the buffer and check for more.
**/
if ((error = DeviceIOWait(MySerReq)))
{
SerialShowError(error);
exit(10);
}
if (EchoMode)
{
putchar(*SerBuffer);
fflush(stdout);
}
BufferExtend(waitBuffer, SerBuffer, 1);
}
else
{ /**
*** Timeout
**/
DeviceIOWait(MyTimeReq);
DeviceIOAbort(MySerReq);
if(VerboseMode)
printf("SerialWait: Timeout Exit line %d\n",__LINE__);
return(-1);
}
}
if(VerboseMode)
printf("SerialWait: Exit line %d\n",__LINE__);
}
/**
*** Return buffer read by the last "Wait" command.
**/
STRPTR SerialWaitBuffer(VOID)
{ if (!(waitBuffer))
{
return((STRPTR) "");
}
else
{
return(BufferBuffer(waitBuffer));
}
}
/**
*** This function implements a terminal mode. It gives the users input
*** to the modem and likewise the modems output to the user, as long as
*** the user doesn't enter Ctrl-\.
**/
VOID SerialTerminal(STRPTR eof, ULONG echo, ULONG lineMode)
{
struct DosPacket *dp;
struct MsgPort *port = NULL;
struct IOExtSer *SerReq = (struct IOExtSer *) DeviceIOReq(MySerReq);
APTR SerSendReq = NULL;
struct IOExtSer *serSendReq;
char buffer[128];
char sendBuffer[256]; /* Twice the size of buffer */
ULONG bufSize = sizeof(buffer);
ULONG status = 10;
BPTR cis = Input();
ULONG sigs;
if (!cis)
{
fprintf(stderr, "Can't use nil: as input device.\n");
exit(10);
}
if (!echo)
{
lineMode = FALSE;
}
if (!lineMode)
{
if (!SetMode(cis, TRUE))
{
fprintf(stderr, "Can't put console into character (raw) mode.\n");
exit(10);
}
bufSize = 128;
}
if ((dp = AllocDosObject(DOS_STDPKT, NULL)))
{ if ((port = CreateMsgPort()))
{ if ((SerSendReq = DeviceIOCreate(sizeof(struct IOExtSer))))
{
serSendReq = (struct IOExtSer *) DeviceIOReq(SerSendReq);
serSendReq->IOSer.io_Device = SerReq->IOSer.io_Device;
serSendReq->IOSer.io_Unit = SerReq->IOSer.io_Unit;
status = 0;
}
}
}
if (status)
{
fprintf(stderr, "Memory error.\n");
goto ExitSerialTerminal;
}
dp->dp_Type = ACTION_READ;
dp->dp_Arg1 = ((struct FileHandle *) BADDR(cis))->fh_Arg1;
dp->dp_Arg2 = (ULONG) buffer;
dp->dp_Arg3 = bufSize;
SendPkt(dp, (struct MsgPort *) ((struct FileHandle *) BADDR(cis))->fh_Type,
port);
SerReq->IOSer.io_Length = 1;
SerReq->IOSer.io_Data = SerBuffer;
DeviceIOSend(MySerReq, CMD_READ);
sigs = (1 << port->mp_SigBit) | SIGBREAKF_CTRL_C | DeviceIOSignal(MySerReq);
for(;;)
{
LONG rsigs;
rsigs = Wait(sigs);
if (rsigs & SIGBREAKF_CTRL_C)
{
fprintf(stderr, "Ctrl-C\n");
status = 5;
DeviceIOAbort(MySerReq);
AbortPkt(port, dp);
WaitPort(port);
goto ExitSerialTerminal;
}
if (rsigs & (1 << port->mp_SigBit))
{ int eofSeen = FALSE;
GetMsg(port);
if (dp->dp_Res1 == -1)
{
fprintf(stderr, "Error %ld while reading input.\n", dp->dp_Res2);
status = 10;
}
if (dp->dp_Res1 == 0)
{
eofSeen = TRUE;
}
else
{
int i, bufLen; /* Extend LF to CR/LF and send resulting string. */
bufLen = 0;
for (i = 0; i < dp->dp_Res1; i++)
{
if ((eof && *eof == buffer[i]) ||
(!eof && !lineMode && buffer[i] == 0x1c))
{
eofSeen = TRUE;
}
if (lineMode && buffer[i] == '\n')
{
sendBuffer[bufLen++] = '\r';
sendBuffer[bufLen++] = '\n';
}
else
{
sendBuffer[bufLen++] = buffer[i];
}
}
if (bufLen > 0)
{
serSendReq->IOSer.io_Length = bufLen;
serSendReq->IOSer.io_Data = sendBuffer;
DeviceIODo(SerSendReq, CMD_WRITE);
}
if (!lineMode && echo)
{
fwrite(sendBuffer, bufLen, 1, stdout);
fflush(stdout);
}
}
if (eofSeen)
{
DeviceIOAbort(MySerReq);
goto ExitSerialTerminal;
}
dp->dp_Type = ACTION_READ;
dp->dp_Arg1 = ((struct FileHandle *) BADDR(cis))->fh_Arg1;
dp->dp_Arg2 = (ULONG) buffer;
dp->dp_Arg3 = bufSize;
SendPkt(dp, (struct MsgPort *) ((struct FileHandle *) BADDR(cis))->fh_Type, port);
}
if (rsigs & DeviceIOSignal(MySerReq))
{
LONG error;
LONG result;
if ((error = DeviceIOWait(MySerReq)))
{
SerialShowError(error);
AbortPkt(port, dp);
WaitPort(port);
goto ExitSerialTerminal;
}
putchar(*SerBuffer);
fflush(stdout);
do
{
DeviceIODo(MySerReq, SDCMD_QUERY);
if ((result = SerReq->IOSer.io_Actual))
{
SerReq->IOSer.io_Data = SerBuffer;
SerReq->IOSer.io_Length = MIN(sizeof(SerBuffer)-1,
SerReq->IOSer.io_Actual);
if ((error = DeviceIODo(MySerReq, CMD_READ)))
{
SerialShowError(error);
exit(10);
}
fwrite(SerBuffer, SerReq->IOSer.io_Actual, 1, stdout);
fflush(stdout);
}
}
while (result);
SerReq->IOSer.io_Length = 1;
SerReq->IOSer.io_Data = SerBuffer;
DeviceIOSend(MySerReq, CMD_READ);
}
}
ExitSerialTerminal:
if (dp)
{
FreeDosObject(DOS_STDPKT, dp);
}
if (port)
{
DeleteMsgPort(port);
}
if (SerSendReq)
{
DeviceIODelete(SerSendReq);
}
if (!lineMode)
{
SetMode(cis, FALSE);
}
if (status)
{
exit(status);
}
}
/**
*** This function shows the current serial parameters.
**/
VOID SerialShowParms(VOID)
{
STRPTR Parity, Protocol;
struct IOExtSer *SerReq;
if (VerboseMode)
printf("\nSerialShowParms\n");
SerReq = (struct IOExtSer *) DeviceIOReq(MySerReq);
printf("\tBaud = %ld\n", SerReq->io_Baud);
printf("\tDataBits = %ld\n", (ULONG) SerReq->io_ReadLen);
printf("\tStopBits = %ld\n", (ULONG) SerReq->io_StopBits);
printf("\tBufSize = %ld\n", SerReq->io_RBufLen);
if (SerReq->io_SerFlags & SERF_PARTY_ON)
{
if (SerReq->io_SerFlags & SERF_PARTY_ODD)
{
Parity = (STRPTR) "Odd";
}
else
{
Parity = (STRPTR) "Even";
}
}
else
{
Parity = (STRPTR) "None";
}
printf("\tParity = %s\n", Parity);
if (SerReq->io_SerFlags & SERF_7WIRE)
{
if (SerReq->io_SerFlags & SERF_XDISABLED)
{
Protocol = (STRPTR) "RTS/CTS";
}
else
{
Protocol = (STRPTR) "RTS/CTS, XON/XOFF";
}
}
else
{
if (SerReq->io_SerFlags & SERF_XDISABLED)
{
Protocol = (STRPTR) "None";
}
else
{
Protocol = (STRPTR) "XON/XOFF";
}
}
printf("\tProtocol = %s\n\n", Protocol);
}
/**
*** Some functions for setting serial parameters.
**/
VOID SerialSetBaud(ULONG Baud)
{
struct IOExtSer *SerReq;
BYTE error;
if (VerboseMode)
printf("\nSerialSetBaud: %d\n", Baud);
SerReq = (struct IOExtSer *) DeviceIOReq(MySerReq);
SerReq->io_Baud = Baud;
if ((error = DeviceIODo(MySerReq, SDCMD_SETPARAMS)))
{
SerialShowError(error);
exit(10);
}
}
VOID SerialSetDataBits(UBYTE DataBits)
{ struct IOExtSer *SerReq = (struct IOExtSer *) DeviceIOReq(MySerReq);
BYTE error;
SerReq->io_ReadLen = SerReq->io_WriteLen = DataBits;
if ((error = DeviceIODo(MySerReq, SDCMD_SETPARAMS)))
{ SerialShowError(error);
exit(10);
}
}
VOID SerialSetStopBits(UBYTE StopBits)
{ struct IOExtSer *SerReq = (struct IOExtSer *) DeviceIOReq(MySerReq);
BYTE error;
SerReq->io_StopBits = StopBits;
if ((error = DeviceIODo(MySerReq, SDCMD_SETPARAMS)))
{ SerialShowError(error);
exit(10);
}
}
VOID SerialSetBufSize(ULONG BufSize)
{ struct IOExtSer *SerReq = (struct IOExtSer *) DeviceIOReq(MySerReq);
BYTE error;
if (BufSize & 0x3f)
{ fprintf(stderr,
"Warning: BufSize must be a multiple of 64, rounding up.\n");
BufSize = (BufSize & 0x3f) + 0x40;
}
SerReq->io_RBufLen = BufSize;
if ((error = DeviceIODo(MySerReq, SDCMD_SETPARAMS)))
{ SerialShowError(error);
exit(10);
}
}
ULONG SerialSetParity(STRPTR Parity)
{ struct IOExtSer *SerReq = (struct IOExtSer *) DeviceIOReq(MySerReq);
BYTE error;
if (stricmp((char *) Parity, "NONE") == 0)
{ SerReq->io_SerFlags &= ~SERF_PARTY_ON;
}
else if (stricmp((char *) Parity, "EVEN") == 0)
{ SerReq->io_SerFlags |= SERF_PARTY_ON;
SerReq->io_SerFlags &= ~SERF_PARTY_ODD;
}
else if (stricmp((char *) Parity, "ODD") == 0)
{ SerReq->io_SerFlags |= (SERF_PARTY_ON|SERF_PARTY_ODD);
}
else
{ return(FALSE);
}
if ((error = DeviceIODo(MySerReq, SDCMD_SETPARAMS)))
{ SerialShowError(error);
exit(10);
}
return(TRUE);
}
ULONG SerialSetProtocol(STRPTR Protocol)
{
struct IOExtSer *SerReq;
BYTE error;
if (VerboseMode)
printf("\nSerialSetProtocol: %s\n", Protocol);
SerReq = (struct IOExtSer *) DeviceIOReq(MySerReq);
if (!(SerialDecodeProtocol(SerReq, Protocol)))
{
return(FALSE);
}
if ((error = DeviceIODo(MySerReq, SDCMD_SETPARAMS)))
{
SerialShowError(error);
exit(10);
}
return(TRUE);
}